package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constant.RedisConstants;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author XinxuanZhuo
 * @since 2024-03-07
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {

    private final StringRedisTemplate stringRedisTemplate;

    /**
     * 保存积分明细
     */
    @Override
    public void addPointsRecord(Long userId, Integer points, PointsRecordType type) {
        // 判断当前积分是否超过上限
        LocalDateTime now = LocalDateTime.now();
        int maxPoints = type.getMaxPoints();

        // 说明有设置积分上限
        int realPoints = points;
        if (maxPoints > 0) {
            // 查询今日已经获得的积分
            LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
            LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);
            // 查询今日已得积分
            int dayCurPoints = queryUserDayPointsByTypeAndDate(userId, dayStartTime, dayEndTime, type);

            //判断是否超过上限
            if (dayCurPoints >= maxPoints) {
                //超过直接结束
                return;
            }
            // 没超过设置具体的值 max - current【if current + points > max】
            if (maxPoints - dayCurPoints < points) {
                realPoints = maxPoints - dayCurPoints;
            }
        }
        // 不设置上限直接保存
        PointsRecord record = new PointsRecord();
        record.setPoints(realPoints);
        record.setUserId(userId);
        record.setType(type);
        save(record);
        // 更新总分到redis
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX +
                now.format(DateUtils.POINTS_BOARD_SUFFIX_FORMATTER);
        // zIncrBy 不存在时相当于add
        stringRedisTemplate.opsForZSet().incrementScore(key,userId.toString(), realPoints);
    }


    /**
     * 查询我的今日积分
     */
    @Override
    public List<PointsStatisticsVO> queryMyPointsToday() {
        // 获取用户ID
        Long userId = UserContext.getUser();
        // 获取今日日期
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime begin = DateUtils.getDayStartTime(now);
        LocalDateTime end = DateUtils.getDayEndTime(now);

        // 构造查询条件 并查询
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(PointsRecord::getUserId, userId)
                .between(PointsRecord::getCreateTime, begin, end);
        List<PointsRecord> list = getBaseMapper().queryUserPointsByDate(wrapper);
        if (CollUtils.isEmpty(list)) {
            return CollUtils.emptyList();
        }
        // 返回
        List<PointsStatisticsVO> vos = new ArrayList<>(list.size());
        for (PointsRecord p : list) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(p.getType().getDesc());
            vo.setMaxPoints(p.getType().getMaxPoints());
            vo.setPoints(p.getPoints());
            vos.add(vo);
        }
        return vos;
    }

    /**
     * 获取用户今日积分总和
     */
    private int queryUserDayPointsByTypeAndDate(Long userId, LocalDateTime start,
                                                LocalDateTime end, PointsRecordType type) {
        // 构造wrapper
        QueryWrapper<PointsRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(PointsRecord::getUserId, userId)
                .eq(type != null, PointsRecord::getType, type)
                .between((start != null && end != null), PointsRecord::getCreateTime, start, end);
        // 调用mapper
        Integer points = this.baseMapper.queryUserPointsByTypeAndDate(queryWrapper);
        return points == null ? 0 : points;
    }


}
